package controller

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"backend/internal/service"
	"github.com/gin-gonic/gin"
)

type AssertController struct {
	assertService *service.AssertService
}

func NewAssertController(service *service.AssertService) *AssertController {
	return &AssertController{assertService: service}
}

// 统一错误处理
func (c *AssertController) handleFabricError(ctx *gin.Context, err error) {
	statusCode := http.StatusInternalServerError
	switch {
	case strings.Contains(err.Error(), "not found"):
		statusCode = http.StatusNotFound
	case strings.Contains(err.Error(), "exists"):
		statusCode = http.StatusConflict
	case strings.Contains(err.Error(), "invalid"):
		statusCode = http.StatusBadRequest
	}

	ctx.JSON(statusCode, gin.H{
		"success": false,
		"error":   err.Error(),
	})
}

// -------------------- 重构后的业务方法 --------------------

func (c *AssertController) Mint(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req MintRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	if err := c.assertService.MintToken(chainID, req.Amount, req.TokenID, req.ClientID); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, BaseResponse{Success: true})
}

func (c *AssertController) CreateSenderHTL(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req CreateSenderHTLRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	htlKey, err := c.assertService.CreateSenderHTL(
		chainID,
		req.ClientID,
		req.Seed,
		req.Timeout,
		req.Amount,
		req.TokenID,
	)
	if err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, HTLResponse{
		BaseResponse: BaseResponse{Success: true},
		HTLKey:       htlKey,
	})
}

func (c *AssertController) CreateReceiverHTL(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req CreateReceiverHTLRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	htlKey, err := c.assertService.CreateReceiverHTL(
		chainID,
		req.HashValue,
		req.ClientID,
		req.Timeout,
		req.Amount,
		req.TokenID,
	)
	if err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, HTLResponse{
		BaseResponse: BaseResponse{Success: true},
		HTLKey:       htlKey,
	})
}

func (c *AssertController) UnlockReceiverHTL(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req UnlockRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	if err := c.assertService.UnlockReceiverHTL(chainID, req.HTLKey, req.Preimage); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, BaseResponse{Success: true})
}

func (c *AssertController) GetAllTokenBalances(ctx *gin.Context) {
	chainID := ctx.Query("chainId")

	balances, err := c.assertService.GetAllTokenBalances(chainID)
	if err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, TokenBalancesResponse{
		BaseResponse: BaseResponse{Success: true},
		Data:         balances,
	})
}

func (c *AssertController) CreateTokenBalances(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req CreateTokenBalancesRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	if err := c.assertService.CreateTokenBalances(chainID, &req.Account); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, BaseResponse{Success: true})
}

func (c *AssertController) UnlockSenderHTL(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req UnlockRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	if err := c.assertService.UnlockSenderHTL(chainID, req.HTLKey, req.Preimage); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, BaseResponse{Success: true})
}

func (c *AssertController) RefundHTL(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req RefundRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	if err := c.assertService.RefundHTL(chainID, req.HTLKey); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, BaseResponse{Success: true})
}

func (c *AssertController) VerifyProof(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req VerifyProofRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	if err := c.assertService.VerifyProof(chainID, req.ProofStr); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, BaseResponse{Success: true})
}

func (c *AssertController) VerifyAndSaveProof(ctx *gin.Context) {
	chainID := ctx.Query("chainId")
	var req VerifyAndSaveProofRequest

	if err := ctx.ShouldBindJSON(&req); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	if err := c.assertService.VerifyAndSaveProof(
		chainID,
		req.ProofID,
		req.ProofData,
	); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, BaseResponse{Success: true})
}

func (c *AssertController) GetAllProofs(ctx *gin.Context) {
	chainID := ctx.Query("chainId")

	proofs, err := c.assertService.GetAllProofs(chainID)
	if err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	ctx.JSON(http.StatusOK, ProofsResponse{
		BaseResponse: BaseResponse{Success: true},
		Data:         proofs,
	})
}

func (c *AssertController) AssertTransfer(ctx *gin.Context) {
	var req CrossChainTransferRequest
	if err := ctx.ShouldBindJSON(&req); err != nil {
		c.handleFabricError(ctx, err)
		return
	}

	// 步骤1: 在源链上创建发送方HTL
	seed := time.Now().UnixNano() // 生成随机种子
	hashR, err := c.assertService.CreateSenderHTL(req.SourceChainID, req.SenderClientID, seed, req.Timeout, req.Amount, req.TokenID)
	if err != nil {
		c.handleFabricError(ctx, fmt.Errorf("创建发送方HTL失败: %w", err))
		return
	}

	// 步骤2: 在目标链上创建接收方HTL
	htlKeyTarget, err := c.assertService.CreateReceiverHTL(req.TargetChainID, hashR, req.ReceiverClientID, req.Timeout, req.Amount, req.TokenID)
	if err != nil {
		c.handleFabricError(ctx, fmt.Errorf("创建接收方HTL失败: %w", err))
		return
	}

	// 步骤3: 在目标链上解锁接收方HTL
	preimage := strconv.FormatInt(seed, 10) // 将seed转换为字符串作为原像
	if err := c.assertService.UnlockReceiverHTL(req.TargetChainID, htlKeyTarget, preimage); err != nil {
		c.handleFabricError(ctx, fmt.Errorf("解锁接收方HTL失败: %w", err))

		// 解锁失败时尝试退款
		if err := c.assertService.RefundHTL(req.TargetChainID, htlKeyTarget); err != nil {
			c.handleFabricError(ctx, fmt.Errorf("解锁失败后尝试退款失败: %w", err))
		}
		return
	}

	// 步骤4: 在源链上解锁发送方HTL
	htlKeySource := fmt.Sprintf("htl_%s_%s", req.SenderClientID, hashR) // 构造源链HTL键
	if err := c.assertService.UnlockSenderHTL(req.SourceChainID, htlKeySource, preimage); err != nil {
		c.handleFabricError(ctx, fmt.Errorf("解锁发送方HTL失败: %w", err))

		// 解锁失败时尝试退款
		if err := c.assertService.RefundHTL(req.SourceChainID, htlKeySource); err != nil {
			c.handleFabricError(ctx, fmt.Errorf("解锁失败后尝试退款失败: %w", err))
		}
		return
	}

	ctx.JSON(http.StatusOK, BaseResponse{Success: true})
}

// -------------------- 请求结构体 --------------------

type MintRequest struct {
	Amount   int    `json:"amount" binding:"required"`
	TokenID  string `json:"tokenID" binding:"required"`
	ClientID string `json:"clientID" binding:"required"`
}

type CreateSenderHTLRequest struct {
	ClientID string `json:"clientID" binding:"required"`
	Seed     int64  `json:"seed" binding:"required"`
	Timeout  int    `json:"timeout" binding:"required,min=60"`
	Amount   int    `json:"amount" binding:"required,gt=0"`
	TokenID  string `json:"tokenID" binding:"required"`
}

type CreateReceiverHTLRequest struct {
	HashValue string `json:"hashValue" binding:"required"`
	ClientID  string `json:"clientID" binding:"required"`
	Timeout   int    `json:"timeout" binding:"required,min=60"`
	Amount    int    `json:"amount" binding:"required,gt=0"`
	TokenID   string `json:"tokenID" binding:"required"`
}

type UnlockRequest struct {
	HTLKey   string `json:"htlKey" binding:"required"`
	Preimage string `json:"preimage" binding:"required"`
}

type CreateTokenBalancesRequest struct {
	Account service.Account `json:"account" binding:"required"`
}

type RefundRequest struct {
	HTLKey string `json:"htlKey" binding:"required"`
}

type VerifyAndSaveProofRequest struct {
	ProofID   string `json:"proofId" binding:"required"`
	ProofData string `json:"proofData" binding:"required"`
}

type CrossChainTransferRequest struct {
	SourceChainID    string `json:"sourceChainID" binding:"required"`
	TargetChainID    string `json:"targetChainID" binding:"required"`
	SenderClientID   string `json:"senderClientID" binding:"required"`
	ReceiverClientID string `json:"receiverClientID" binding:"required"`
	TokenID          string `json:"tokenID" binding:"required"`
	Amount           int    `json:"amount" binding:"required,gt=0"`
	Timeout          int    `json:"timeout" binding:"required,min=60"`
}

// -------------------- 响应结构体 --------------------
type HTLResponse struct {
	BaseResponse
	HTLKey string `json:"htlKey"`
}

type TokenBalancesResponse struct {
	BaseResponse
	Data []service.TokenBalance `json:"data"`
}

type ProofsResponse struct {
	BaseResponse
	Data []map[string]interface{} `json:"data"`
}
